<template>
  <LayoutComponet
    :id="option.id"
    ref="layoutRef"
    :data
    :option
    :pagination
    :checked-row-keys
    :search-form
    :search-visible
    :loading
    :size
    class="nv-crud"
    @trigger="layoutEventHandler"
  >
    <template #search>
      <SearchForm
        v-if="option.searchForm !== false"
        ref="searchRef"
        v-model:search-form="searchForm"
        v-model:loading="loading"
        :option
        :size
        @search="props.onSearch?.(() => loading = false)"
      >
        <template v-for="(_, name) in slots" #[name]="slotData">
          <slot :name v-bind="slotData || {}" />
        </template>
      </SearchForm>
    </template>
    <template #actionbar>
      <Actionbar
        v-if="option.actionbar !== false"
        :option="option.actionbar"
        :size
        @add="actions.rowAdd"
      >
        <template v-for="name in ['actionbar', 'actionbar_pre']" #[name]="slotData">
          <slot :name v-bind="slotData || {}" />
        </template>
      </Actionbar>
    </template>
    <template #toolbar>
      <Toolbar
        v-if="option.toolbar !== false"
        v-model:striped="striped"
        v-model:loading="loading"
        v-model:size="size"
        :fullscreen="isFullscreen"
        :option="option.toolbar"
        @update:fullscreen="toggleFullscreen"
        @refresh="props.onRefresh?.(() => loading = false)"
        @export="props.onExport"
        @import="props.onImport"
      >
        <template v-for="name in ['toolbar', 'toolbar_pre']" #[name]="slotData">
          <slot :name v-bind="slotData || {}" />
        </template>
      </Toolbar>
    </template>

    <template #multi-select-bar>
      <NTag
        v-if="multiSelectBarVisible"
        type="primary"
        class="nv-crud__multi-select-bar"
        v-bind="option.multiSelectBar"
      >
        <component
          :is="() => option.multiSelectBar!.renderTip!(checkedRowKeys.length)"
          v-if="option.multiSelectBar?.renderTip"
        />
        <template v-else>
          已选择 <strong>{{ checkedRowKeys.length }}</strong> 项
        </template>
        <slot name="multi-select-bar" />
      </NTag>
    </template>

    <template #table>
      <DataTable
        v-model:checked-row-keys="checkedRowKeys"
        :data="props.data"
        :columns="dataTableColumns"
        :loading
        :option="{ ...option, size, striped }"
        :pagination="pagination"
        @view="actions.rowView"
        @edit="actions.rowEdit"
        @del="actions.rowDel"
        @load="props.onLoad"
        @scroll="props.onScroll"
        @update:filters="props['onUpdate:filters']"
        @update:page="props['onUpdate:page']"
        @update:page-size="props['onUpdate:pageSize']"
        @update:sorter="props['onUpdate:sorter']"
      >
        <template v-for="(_, name) in slots" #[name]="slotData">
          <slot :name v-bind="slotData || {}" />
        </template>
      </DataTable>

      <DataForm
        ref="formRef"
        v-model:form="form"
        v-model:form-visible="formVisible"
        v-model:submit-loading="submitLoading"
        :option
        :form-mode
        :size
        @row-save="props.onRowSave"
        @row-update="props.onRowUpdate"
      >
        <template v-for="(_, name) in slots" #[name]="slotData">
          <slot :name v-bind="slotData || {}" />
        </template>
      </DataForm>
    </template>

    <template v-for="(_, name) in layoutSlots" #[name]="slotData">
      <slot :name v-bind="slotData || {}" />
    </template>
  </LayoutComponet>
</template>

<script setup lang="ts">
import type { MaybeElement } from '@vueuse/core'
import type { DataTableRowKey } from 'naive-ui'
import type { Expose as NvSearchInst } from './components/search/types'
import type { Expose as DataFormInst } from './form/types'
import type { NvCrudEmits, NvCrudInst, NvCrudProps } from './types'
import type { RowData, Size } from '@/types'
import { useFullscreen } from '@vueuse/core'
import { NTag } from 'naive-ui'
import { computed, ref } from 'vue'
import { Actionbar, DataTable, SearchForm, Toolbar } from './components'
import DataForm from './form/Index.vue'
import { useActions } from './use-actions'
import { useColumns } from './use-columns'
import { useLayout } from './use-layout'

const props = defineProps<NvCrudProps>()
const emits = defineEmits<NvCrudEmits>()
const slots = defineSlots()

const loading = defineModel<boolean>('loading', { default: false })
const form = defineModel<RowData>('form', { default: () => ({}) })
const submitLoading = defineModel<boolean>('submitLoading', { default: false })
const searchForm = defineModel<RowData>('searchForm', { default: () => ({}) })
const checkedRowKeys = defineModel<DataTableRowKey[]>('checkedRowKeys', { default: () => [] })

const { LayoutComponet, layoutEventHandler, layoutSlots, searchVisible } = useLayout(props, emits, slots)

const striped = ref(props.option.striped || false)
const size = ref<Size>(props.option.size || 'medium')
const layoutRef = ref<MaybeElement>()
const { isFullscreen, toggle: toggleFullscreen } = useFullscreen(layoutRef)

const formRef = ref<DataFormInst>()
const { formVisible, formMode, ...actions } = useActions(props, form, formRef)

const { dataTableColumns } = useColumns(props, slots, size, actions)

const multiSelectBarVisible = computed(() => {
  const { selection, multiSelectBar } = props.option
  if (!selection || selection.multiple === false) {
    return false
  }
  if (!multiSelectBar) {
    return false
  }
  return true
})

const searchRef = ref<NvSearchInst>()

defineExpose<NvCrudInst>({
  ...actions,
  closeForm: () => formRef.value!.closeForm(),
  getFormRef: () => formRef.value,
  getSearchRef: () => searchRef.value,
})
</script>

<style lang="scss">
.nv-crud__multi-select-bar {
  margin-bottom: 5px;
  strong {
    font-size: 16px;
  }
}
</style>
